/*
    获取access_token
    唯一，有效期2小时，提前5分钟请求
    每天调用2000次
    请求地址：https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
    设计思想：
        1. 首次本地没有，发送请求获取acess_token，保存下来（本地文件）
        2. 第二次以后
            - 先去本地读取文件，判断它是否过期(isValidAccessToken)
                - 过期
                    - 重新请求token(getAccessToken)，保存覆盖原来的文件（保证文件是唯一的）(saveAccessToken)
                - 没有过期
                    - 直接使用

    整体思路：
        读取本地文件（readAccessToken）
            - 本地有文件
                - 判断它是否过期(isValidAccessToken)

                  - 过期了
                     - 重新请求token(getAccessToken)，保存覆盖原来的文件（保证文件是唯一的）(saveAccessToken)
                  - 没有过期
                     - 直接使用
             - 本地有文件
                - 发送请求获取access_token(getAccessToken), 保存下来（本地文件）（saveAccessToken），直接使用

 */



// 引入config文件
const{appID, appsecret} = require('../config');

console.log(appID, appsecret);

// 只要引入request-promise-native
const rp = require('request-promise-native');

// 引入fs模块(异步的)
const {writeFile, readFile} = require('fs');

// 引入menu模块
const menu = require('./menu');

// 引入公用api地址前缀
const api = require('../utils/api');

// 引入工具函数
const {writeFileAsync,readFileAsync} = require('../utils/tool');


//定义类，获取accesstoken
class Wechat {
    constructor() {

    }

    /**
     * 用来获取token
     *
     */
    getAccessToken() {

        // 定义请求地址
        const url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appID}&secret=${appsecret}`


        return new Promise((resolve, reject) => {
            // 在服务器中进行请求，不能用ajax
            // request request-promise-native
            rp({
                method: 'GET',
                url, // 属性名和值的变量名相同，可以简写一个
                json: true
            }).then(res => {
                console.log(res);

                // 设置token的过期时间
                res.expires_in = Date.now() + (res.expires_in - 300) * 1000;

                // 想promise对象的状态改成成功的状态
                resolve(res);

            })
            .catch(err => {
                console.log(err)
                reject('getAccessToken方法除了问题：' + err);
            })
        })


    }


    /**
     * 保存token的方法
     * @param accessToken 要保存的凭据
     */
    saveAccessToken(accessToken) {
        return writeFileAsync(accessToken, 'accessToken.txt');
    }


    /**
     * 读取token的方法
     */
    readAccessToken() {
        return readFileAsync('accessToken.txt');
    }

    /**
     * 判断token是否有效
     * @param data
     */
    isValidAccessToken(data) {
        // 检测传入的参数是否有效
        if (!data && data.access_token && !data.expires_in) {
            // 代表access_token无效的
            return false;
        }

        // 检测access_token是否在有效期内
        // if(data.expires_in < Date.now()){
        //     // 过期了
        //     return false;
        // }else{
        //     return true;
        // }
        // if else 代替简写方式
        return data.expires_in < Date.now();

    }

    /**
     * 用来获取没有过期的access_token
     * @return promise
     */
    fetchAccessToken() {
        // 优化
        if (this.access_token && this.expires_in && this.isValidAccessToken(this)) {
            // 说明之前保存过access_token, 并且它是有效的，直接使用
            return Promise.resolve({
                access_token: this.access_token,
                expires_in: expires_in,

            })
        }
        return this.readAccessToken()
            .then(async res => {
                // 本地有文件
                // 判断它是否过期
                if (this.isValidAccessToken(res)) {
                    // 有效的
                    resolve(res);
                } else {
                    // 本地没有文件
                    // 发送请求获取access_token(getAccessToken)
                    const res = await this.getAccessToken()
                    //保存下来（本地文件）（saveAccessToken），直接使用
                    await this.saveAccessToken(res);
                    // 将请求回来的token返回出去
                    //  resolve(res);
                    return Promise.resolve(res);
                }

            })
            .catch(async err => {
                // 本地没有文件
                // 发送请求获取access_token(getAccessToken)
                const res = await this.getAccessToken()
                //保存下来（本地文件）（saveAccessToken），直接使用
                await this.saveAccessToken(res);
                // 将请求回来的token返回出去
                // resolve(res);
                return Promise.resolve(res);
            })
            .then(res => {
                // 将token挂在到this上面
                this.access_token = res.access_token;
                this.expires_in = res.expires_in;
                // 返回rs包装一层promise对象（此对象为成功对象）
                // 是this.readAccessToken（）最终返回值
                return Promise.resolve(res);
            })
    }

    /**
     * 用来创建自定义菜单
     * @param menu
     * @return {Promise<any>}
     */
    createMenu(menu) {
        return new Promise(async (resolve, reject) => {
            try {
                // 获取token
                const data = await this.fetchAccessToken();
                //  定义请求的地址
                const url = `https://api.weixin.qq.com/cgi-bin/menu/create?access_token=${data.access_token}`;
                // 发送请求
                const result = await rp({
                    method: 'POST',
                    url,
                    json: true,
                    body: menu
                });
                resolve(result);
            } catch (e) {
                reject('createMenu方法出了问题：' + e);
            }

        })
    }

    /**
     * 用来删除 自定义菜单
     * @param menu
     * @return {Promise<any>}
     */
    deleteMenu() {
        return new Promise(async (resolve, reject) => {
            try {
                const data = await this.fetchAccessToken();
                console.log('哈哈哈哈我是删除菜单方法：******');

                // 定义请求的地址
                const url = `https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=${data.access_token}`;
                console.log(url);
                // 发送请求
                const result = await rp({
                    method: 'POST',
                    url,
                    json: true
                });
                resolve(result);
            } catch (e) {
                reject('deleteMenu方法出了问题：' + e);
            }
        })
    }

    /**
     * 用来获取jsapi_ticket
     *
     */
    getJsApiTicket() {
        return new Promise(async (resolve, reject) => {
            // 获取access_token
            const data = await this.fetchAccessToken();
            // 定义请求地址
            const url = `${api.ticket}&access_token=${data.access_token}`


            // 在服务器中进行请求，不能用ajax
            // request request-promise-native
            rp({
                method: 'GET',
                url, // 属性名和值的变量名相同，可以简写一个
                json: true
            }).then(res => {
                console.log(res);
                resolve({
                    ticket: res.ticket,
                    expires_in: Date.now() + (res.expires_in -300) *1000
                })

                // 将promise对象的状态改成成功的状态
                resolve(res);

            })
            .catch(err => {
                console.log(err)
                reject('getJsApiTicket方法除了问题：' + err);
            })
        })


    }


    /**
     * 保存jsapi_ticket的方法
     * @param ticket 要保存的票据
     */
    saveJsApiTicket(ticket) {
        return writeFileAsync(ticket, 'ticket.txt');
    }


    /**
     * 读取jsapi_ticket的方法
     */
    readJsApiTicket() {
        return readFileAsync('ticket.txt');
    }

    /**
     * 判断jsapi_ticket是否有效
     * @param data
     */
    isValidJsApiTicket(data) {
        // 检测传入的参数是否有效
        if (!data && data.ticket && !data.expires_in) {
            // 代表ticket无效的
            return false;
        }

        return data.expires_in < Date.now();
    }

    /**
     * 用来获取没有过期的jsapi_ticket
     * @return promise
     */
    fetchJsApiTicket() {
        // 优化
        if (this.ticket && this.ticket_expires_in && this.isValidJsApiTicket(this)) {
            // 说明之前保存过ticket, 并且它是有效的，直接使用
            return Promise.resolve({
                ticket: this.ticket,
                expires_in: expires_in,

            })
        }
        return this.readJsApiTicket()
            .then(async res => {
                // 本地有文件
                // 判断它是否过期
                if (this.isValidJsApiTicket(res)) {
                    // 有效的
                    resolve(res);
                } else {
                    // 本地没有文件
                    // 发送请求获取ticket(getJsApiTicket)
                    const res = await this.getJsApiTicket()
                    //保存下来（本地文件）（saveAccessToken），直接使用
                    await this.saveJsApiTicket(res);
                    // 将请求回来的ticket返回出去
                    //  resolve(res);
                    return Promise.resolve(res);
                }

            })
            .catch(async err => {
                // 本地没有文件
                // 发送请求获取ticket(getJsApiTicket)
                const res = await this.getJsApiTicket()
                //保存下来（本地文件）（saveAccessToken），直接使用
                await this.saveJsApiTicket(res);
                // 将请求回来的token返回出去
                // resolve(res);
                return Promise.resolve(res);
            })
            .then(res => {
                // 将token挂在到this上面
                this.ticket = res.ticket;
                this.ticket_expires_in = res.expires_in;
                // 返回rs包装一层promise对象（此对象为成功对象）
                // 是this.readJsApiTicket（）最终返回值
                return Promise.resolve(res);
            })
    }



}

(async () => {

    // 模拟测试
    const w = new Wechat();
   /* // 删除之前定义的菜单
    let result = await w.deleteMenu();
    console.log(result);
    // 创建新的菜单
    await w.createMenu(menu);
    console.log(result)*/

   const data = await w.fetchJsApiTicket();
   console.log(data);
})()



// w.getAccessToken();

module.exports = Wechat;



